import { _decorator, Component } from 'cc';
import { TICK_RATES } from '../shared';

const { ccclass } = _decorator;

export type TickFn = (dt: number) => void;

interface TickEntry {
  name: string;
  hz: number;
  fn: TickFn;
  interval: number;
  accumulator: number;
}

/**
 * 核心调度器，统一驱动 60Hz（渲染/输入）以及副频率（AI/导航/统计）。
 */
export class ClockCore {
  private entries: Map<string, TickEntry> = new Map();
  private rafId: number | null = null;

  register(name: string, hz: number, fn: TickFn): void {
    const safeHz = Math.max(0.0001, hz);
    this.entries.set(name, {
      name,
      hz: safeHz,
      fn,
      interval: 1 / safeHz,
      accumulator: 0,
    });
  }

  unregister(name: string): void {
    this.entries.delete(name);
  }

  clear(): void {
    this.entries.clear();
  }

  /** 手动步进，用于测试。 */
  step(dt: number): void {
    for (const entry of this.entries.values()) {
      entry.accumulator += dt;
      if (entry.accumulator >= entry.interval) {
        entry.fn(entry.accumulator);
        entry.accumulator = entry.accumulator % entry.interval;
      }
    }
  }

  /**
   * 以 requestAnimationFrame 驱动 60Hz 主循环（在非 Cocos 环境或工具脚本中也可使用）。
   * 在 Cocos 组件中通常不需要调用此方法。
   */
  startRafLoop(): void {
    if (this.rafId !== null) return;
    let last = performance.now();
    const loop = () => {
      const now = performance.now();
      const dt = Math.min(0.1, (now - last) / 1000); // clamp 100ms
      last = now;
      this.step(dt);
      this.rafId = requestAnimationFrame(loop);
    };
    this.rafId = requestAnimationFrame(loop);
  }

  stopRafLoop(): void {
    if (this.rafId !== null) {
      cancelAnimationFrame(this.rafId);
      this.rafId = null;
    }
  }
}

@ccclass('Clock')
export class Clock extends Component {
  private core = new ClockCore();

  onEnable() {
    this.core.register('render', TICK_RATES.render, (dt) => {
      this.node.emit('clock:render', dt);
    });
    this.core.register('ai', TICK_RATES.ai, (dt) => {
      this.node.emit('clock:ai', dt);
    });
    this.core.register('navigation', TICK_RATES.navigation, (dt) => {
      this.node.emit('clock:nav', dt);
    });
    this.core.register('stats', TICK_RATES.stats, (dt) => {
      this.node.emit('clock:stats', dt);
    });
  }

  onDisable() {
    this.core.clear();
  }

  update(dt: number) {
    this.core.step(dt);
  }

  /** 对外暴露注册接口，便于模块自定义 tick。 */
  register(name: string, hz: number, fn: TickFn): void {
    this.core.register(name, hz, fn);
  }

  unregister(name: string): void {
    this.core.unregister(name);
  }

  /** 供外部测试使用：开始一个 RAF 循环驱动本 Clock 的核心。 */
  startRafLoop(): void {
    this.core.startRafLoop();
  }

  stopRafLoop(): void {
    this.core.stopRafLoop();
  }
}

